#pragma once
#include <Rz/IObject.h>
#include <Rz/Singleton.h>
#include <Rz/EnumFlags.h>

#if defined(RZ_INCLUDE_PTRMANAGER) && defined(RZ_INCLUDE_LOGGER)
#	ifndef RZ_INCLUDE_RTTI
#		error "[RZ] You must define RZ_INCLUDE_RTTI to run PtrManager properly!"
#	endif
#	define RZ_PTRMANAGER			::Rz::Diagnostics::PtrManagerWrapper _pmw
#	define RZ_PTRMANAGER_ADDREF(p)	::Rz::Diagnostics::PtrManager::GetInstance().AddReference(p)
#	define RZ_PTRMANAGER_REMREF(p)	::Rz::Diagnostics::PtrManager::GetInstance().RemoveReference(p)
#	define RZ_PTRMANAGER_PAUSE()	::Rz::Diagnostics::PtrManager::GetInstance().Pause()
#	define RZ_PTRMANAGER_RESUME()	::Rz::Diagnostics::PtrManager::GetInstance().Resume()
#else
#	define RZ_PTRMANAGER
#	define RZ_PTRMANAGER_ADDREF(p)
#	define RZ_PTRMANAGER_REMREF(p)
#	define RZ_PTRMANAGER_PAUSE()
#	define RZ_PTRMANAGER_RESUME()
#endif

// PtrManager without Logger doesn't make sense
#if defined(RZ_INCLUDE_PTRMANAGER) && defined(RZ_INCLUDE_LOGGER)

namespace Rz { namespace Diagnostics {

class PtrManager final :
	public Singleton<PtrManager>
{
	friend class Singleton<PtrManager>;

	public:
		RZ_MARK_AS_SINGLETON(PtrManager);

		enum class Options
		{
			None					= RZ_DEFINE_ZERO_ENUMFLAG,
			LogReferenceAdd			= RZ_DEFINE_ENUMFLAG(0),
			LogReferenceRemove		= RZ_DEFINE_ENUMFLAG(1),

			LogAll = LogReferenceAdd | LogReferenceRemove
		};

		RZ_MARK_AS_ENUMFLAGS_FRIEND(Options);

		void AddReference(const IObject* obj);
		void RemoveReference(const IObject* obj);
		void PrintMemoryMap() const;

		void Pause(bool pause = true);
		void Resume();

	private:
		PtrManager();
		~PtrManager();
		FILE* _stream;
		Options _options;
		bool _paused;
};

class PtrManagerWrapper
{
	public:
		~PtrManagerWrapper()
		{
			PtrManager::GetInstance().PrintMemoryMap();
		}
};

} }

#endif
